package viable_socket;

use Socket;

sub new
{
    my ($self,$cr_socket)=@_;
    my $o={
	    _create_sock => $cr_socket, #ref. to a function wich will create socket for us :)
	};
    $$o{'socket'}=$cr_socket->();
    bless $o;
}

sub connect
{
    my ($self)=shift;
    my $sock=$self->{'socket'};
    my $cr=$self->{'_create_sock'};
    $sock=$cr->();
    $self->{'socket'}=$sock;
    $sock;
}

sub reconnect
{
    my $self=shift;
    shutdown ($self->{'socket'},2);
    $self->connect();
    return $self->{'socket'};
}

sub _viable_do
{
    my $self=shift;
    my $func=shift;
    my $ret;

    for (1..3)
    {
	$ret=$func->(@_);
	return $ret if (defined $ret);
	$self->reconnect();
    }

    return $ret;
}

sub recv
{
    my ($self,$scalar,$length,$flags)=@_;
    my $s=$self=>{'socket'};

    return $self->_viable_do(\&recv,$s,$scalar,$length,$flags);
}

sub send
{
    my ($self,$msg,$flags,$to)=@_;
    my $s=$self->{'socket'};

    return $self->_viable_do(\&send,$s,$msg,$flags,$to) if (defined $to);
    return $self->_viable_do(\&send,$s,$msg,$flags);
}

sub _print_to_sock
{
    my ($socket,$str)=@_;
    my $ret;

    eval
    {
	$ret=(print $socket $str);
    };
    if ($@)
    {
	return 0;
    }
    return 1 if ($ret);
    return 0;
}

sub readline
{
    my ($self)=@_;
    my $s=$self->{'socket'};
    my $ret;

    for (1..3)
    {
	my $peer=getpeername($s);
	if (!defined $peer)
	{
	    $self->reconnect();
	    $s=$self->{'socket'};
	}
	$ret=<$s>;
	$peer=getpeername($s);
	last if (($ret) or (defined $peer));
    }
    return $ret;
}

sub print
{
    my ($self,$str)=@_;
    $self->_viable_do(\&_print_to_sock,$self->{'socket'},$str);
}


1;
